local SUtils = import('/lua/ai/sorianutilities.lua')

local PingLocked = false
local PingMarkers = {}
MaxPingMarkers = 15
--On first ping, send data to the user layer telling it the maximum allowable markers per army
Sync.MaxPingMarkers = MaxPingMarkers

function AnimatePingMesh(entity)
    local time = 0
    local ascending = true
    while entity do
        local orien = entity:GetOrientation()
        entity:SetScale(MATH_Lerp(math.sin(time), -.5, 0.5, .3, .5))
        time = time + .3
        WaitSeconds(.001)
    end
end

function SpawnPing(data)
    if not PingLocked then
        if data.Marker and PingMarkers[data.Owner] and table.getsize(PingMarkers[data.Owner]) >= MaxPingMarkers then
            return
        elseif data.Marker and not PingMarkers[data.Owner] then
            PingMarkers[data.Owner] = {}
        end
        PingLocked = true

        if data.Marker and GetPingID(data.Owner) then
            data.ID = GetPingID(data.Owner)
            PingMarkers[data.Owner][data.ID] = data
        else
            local Entity = import('/lua/sim/Entity.lua').Entity
            data.Location[2] = data.Location[2]+2
            local pingSpec = {Owner = data.Owner, Location = data.Location}
            local ping = Entity(pingSpec)
            Warp(ping, Vector(data.Location[1], data.Location[2], data.Location[3]))
            ping:SetVizToFocusPlayer('Always')
            ping:SetVizToEnemies('Never')
            ping:SetVizToAllies('Always')
            ping:SetVizToNeutrals('Never')
            ping:SetMesh('/meshes/game/ping_'..data.Mesh)
            local animThread = ForkThread(AnimatePingMesh, ping)
            ForkThread(function() 
                WaitSeconds(data.Lifetime)
                KillThread(animThread)
                ping:Destroy()
            end)
        end

        SendData(data)

        # Callbacks to allied brains
        for num,brain in ArmyBrains do
            if data.Owner + 1 ~= num and IsAlly( num, data.Owner + 1) then
                ArmyBrains[num]:DoPingCallbacks( data )
				if not SUtils.IsAIArmy(data.Owner + 1) then
					ArmyBrains[num]:DoAIPing( data )
				end
            end
        end

        ForkThread(function() WaitSeconds(1) PingLocked = false end)
    end
end

function GetPingID(owner)
    for i = 1, MaxPingMarkers do
        if not PingMarkers[owner][i] then
            return i
        end
    end
    return false
end

function OnArmyDefeat(armyID)
    armyID = armyID - 1
    if PingMarkers[armyID] then
        for i, v in PingMarkers[armyID] do
            UpdateMarker({Action = 'delete', ID = i, Owner = v.Spec.Owner})
        end
    end
end

function OnArmyChange()
    Sync.MaxPingMarkers = MaxPingMarkers
    LOG('syncing max ping markers: ', MaxPingMarkers)
    --Flush all of the current markers on the UI side
    if not Sync.Ping then Sync.Ping = {} end
    table.insert(Sync.Ping, {Action = 'flush'})
    --Add All of the relevant marker data on the next sync
    if GetFocusArmy() != -1 then
        ForkThread(function()
            for ownerID, pingTable in PingMarkers do
                if IsAlly(ownerID+1, GetFocusArmy()) then
                    for pingID, ping in pingTable do
                        ping.Renew = true
                        SendData(ping)
                    end
                end
            end
        end)
    end
end

function OnAllianceChange()
    OnArmyChange()
end

function UpdateMarker(data)
    if PingMarkers[data.Owner][data.ID] or data.Action == 'renew' then
        if data.Action == 'delete' then 
            if OkayToMessWithArmy(data.Owner+1) then
                PingMarkers[data.Owner][data.ID] = nil
            else
                return
            end
        elseif data.Action == 'move' then
            PingMarkers[data.Owner][data.ID].Location = data.Location
        elseif data.Action == 'rename' then
            PingMarkers[data.Owner][data.ID].Name = data.Name
        elseif data.Action == 'renew' then
            ForkThread(function()
                for ownerID, pingTable in PingMarkers do
                    if IsAlly(ownerID+1, GetFocusArmy()) then
                        for pingID, ping in pingTable do
                            ping.Renew = true
                            SendData(ping)
                        end
                    end
                end
            end)
            return
        end
        SendData(data)
    end
end

function SendData(data)
    if GetFocusArmy() != -1 then
        if IsAlly(data.Owner+1, GetFocusArmy()) then
            if not Sync.Ping then Sync.Ping = {} end
            table.insert(Sync.Ping, data)
        end
    end
end